package control;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class DocumentNoun {
	
	private Map<String,Map<String,Integer>> docNounMap;
	private Map<String, Integer> nounCntMap;
	private Set<String> nounList;
	private int numOfDoc;
	private Map<String, Integer> maxNounCntMap;
	private Map<String, Integer> numOfDocNounInMap;
	
	
	public DocumentNoun() {
		docNounMap = new HashMap<String,Map<String,Integer>>();
		maxNounCntMap = new HashMap<String,Integer>();
		nounList = new HashSet<String>();
		numOfDocNounInMap = new HashMap<String,Integer>();
		numOfDoc = 0;
	}
	
	/** 
	 * Get file to buffer
	 * 
	 * @param file
	 * @return
	 * @throws FileNotFoundException
	 */
	public BufferedReader readFile(File file) throws Exception {
		BufferedReader bf;
		try {
			  bf = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"));
		} catch (Exception e) {
			throw e;
		}
		return bf; 				
	}
	
	/**
	 * 
	 * @param dir
	 * @throws Exception
	 */
	public void getNouns(File dir) throws Exception {

		File outFile = new File("all_nc.txt");
		BufferedWriter output = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile),"UTF-8"));
		
		// We read each file in folders and get the nouns
		for (File inFile : dir.listFiles()) {

			String fileN = inFile.getName().substring(0,
					inFile.getName().length() - 5);
			String str;
			
			nounCntMap = new HashMap<String, Integer>();
			
			
			BufferedReader input = readFile(inFile);
			
			// read characters
			while (input.read() != -1)
			{
				str = input.readLine();

				int st = str.indexOf('[');
				int end = str.indexOf(']');
				if ((st > -1) && (end > -1) && (st < end)) {
					String stNew = str.substring((st + 1), end);

					if (stNew.equals("Noun")) {
						String noun = str.split("\\[")[0].split(" ")[str.split("\\[")[0].split(" ").length - 1];

						if (str.length() >= (end + 7))
						{	
							if (!str.substring((end + 3), (end + 7)).equals("Acro") &&
								!str.substring((end + 3),(end + 7)).equals("Prop") &&
								!str.substring((end + 3),(end + 7)).equals("Abbr"))
							{
								int count = nounCntMap.containsKey(noun) ? nounCntMap.get(noun) : 0;
								nounCntMap.put(noun, count + 1);
								nounList.add(noun);
							}
						}	
					}
				}

			}
			docNounMap.put(inFile.getName(), nounCntMap);

			// Below code does create Noun Count files
			File oFile = new File(dir.getName().substring(0,dir.getName().length() - 3) + "_" + fileN + "_nc.txt");
			BufferedWriter out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(oFile),"UTF-8"));

			List<String> listNoun = new ArrayList<String>(nounCntMap.keySet());
			List<Integer> listNumOfNoun = new ArrayList<Integer>(nounCntMap.values());

			for (int t = 0; t < nounCntMap.size(); t++) {
				out.append(listNoun.get(t) + "\t" + listNumOfNoun.get(t) + "\n");
				output.append(inFile.getName() + "\t" + listNoun.get(t) + "\t" + listNumOfNoun.get(t) + "\n");
			}
			out.close();
		}
		output.close();
	}
	
	public void createMatrix() throws Exception {
        Iterator MapFileIterator = docNounMap.entrySet().iterator();
        
        numOfDoc = 0;
        while (MapFileIterator.hasNext()) {
	        Map.Entry pairs = (Map.Entry)MapFileIterator.next();
	        numOfDoc++;
        }
        
	    Iterator<String> SetIterator = nounList.iterator();
	    while(SetIterator.hasNext()) {
	        String setElement = SetIterator.next();
	        int cntDoc = 0;
	        Iterator MapIterator = docNounMap.entrySet().iterator();
	        while (MapIterator.hasNext()) {
		        Map.Entry pairs = (Map.Entry)MapIterator.next();
		        String fileName = pairs.getKey().toString();
		        if ( ((Map<String, Integer>)pairs.getValue()).containsKey(setElement) ) {
		        	int cntValue = ((Map<String, Integer>)pairs.getValue()).get(setElement);
		        	cntDoc++;
		        	if (null==maxNounCntMap.get(setElement) || cntValue > maxNounCntMap.get(setElement)) {
		        		maxNounCntMap.put(setElement, cntValue);
		        	}
		        }
	        }
	        numOfDocNounInMap.put(setElement, cntDoc);
	    }
	}		
	
	public void writeFile(File outFile) throws Exception {
		BufferedWriter output = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile),"UTF-8"));
		
        Iterator MapFileIterator = docNounMap.entrySet().iterator();
        String header = "";
        while (MapFileIterator.hasNext()) {
	        Map.Entry pairs = (Map.Entry)MapFileIterator.next();
	        header = header + pairs.getKey().toString() + ";";  
        }
        header = header.substring(0,header.length()-1);
        output.append(header + "\n");
        
	    Iterator<String> SetIterator = nounList.iterator();
	    while(SetIterator.hasNext()) {
	        String setElement = SetIterator.next();
	        String line = setElement + ";";
	        Iterator MapIterator = docNounMap.entrySet().iterator();
	        while (MapIterator.hasNext()) {
		        Map.Entry pairs = (Map.Entry)MapIterator.next();
		        String fileName = pairs.getKey().toString();
		        if ( ((Map<String, Integer>)pairs.getValue()).containsKey(setElement) ) {
		        	int cntValue = ((Map<String, Integer>)pairs.getValue()).get(setElement);
		        	int maxNounCnt = maxNounCntMap.get(setElement);
		        	int numOfDocNounIn = numOfDocNounInMap.get(setElement)+1;
		        	double tfIdt = ((double) cntValue/ (double) maxNounCnt) * Math.log( (double) numOfDoc/ (double)numOfDocNounIn);
		        	line = line + tfIdt +";";
		        } else {
		        	line = line + 0 + ";";
		        }
	        }
	        line = line.substring(0,line.length()-1);
	        output.append(line + "\n");
	    }
	    output.close();    
	}		

	public void printNestedMap(Map<String, Map<String, Integer>> map)
	{
	  Iterator it = map.entrySet().iterator();
	    while (it.hasNext()) {
	        Map.Entry pairs = (Map.Entry)it.next(); // <- pairs.getValue() is a map
	        System.out.println("Key1: " + pairs.getKey());
	        //print the inner Map
	        printMap((Map<String, Integer>)pairs.getValue());
	        it.remove(); // avoids a ConcurrentModificationException
	    }
	}

	public void printMap(Map<String, Integer> map)
	{
	   Iterator it = map.entrySet().iterator();
	   while(it.hasNext())
	   {
	      Map.Entry pairs = (Map.Entry)it.next(); // <- pairs.getValue() is a String
	      System.out.println("Key2: " + pairs.getKey() + " Value2: " + pairs.getValue());
	      it.remove();
	   }
	}

	public Map<String, Map<String, Integer>> getDocNounMap() {
		return docNounMap;
	}

	public void setDocNounMap(Map<String, Map<String, Integer>> docNounMap) {
		this.docNounMap = docNounMap;
	}

	public Set<String> getNounList() {
		return nounList;
	}

	public void setNounList(Set<String> nounList) {
		this.nounList = nounList;
	}

	public int getNumOfDoc() {
		return numOfDoc;
	}

	public void setNumOfDoc(int numOfDoc) {
		this.numOfDoc = numOfDoc;
	}

	public Map<String, Integer> getMaxNounCntMap() {
		return maxNounCntMap;
	}

	public void setMaxNounCntMap(Map<String, Integer> maxNounCntMap) {
		this.maxNounCntMap = maxNounCntMap;
	}

	public Map<String, Integer> getNumOfDocNounInMap() {
		return numOfDocNounInMap;
	}

	public void setNumOfDocNounInMap(Map<String, Integer> numOfDocNounInMap) {
		this.numOfDocNounInMap = numOfDocNounInMap;
	}

	@Override
	public String toString() {
		return "DocumentNoun [docNounMap=" + docNounMap + ", nounList=" + nounList + ", numOfDoc="
				+ numOfDoc + ", maxNounCntMap=" + maxNounCntMap
				+ ", numOfDocNounInMap=" + numOfDocNounInMap + "]";
	}
	
}